package org.cogaen.input;

import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import org.cogaen.core.Core;
import org.cogaen.event.EventManager;
import org.cogaen.task.AbstractTask;
import org.cogaen.task.TaskManager;

public class PollingKeyboardControllerSource {

	private List<Key> actions = new ArrayList<Key>();
	private Key[] hAxis = new Key[2];
	private Key[] vAxis = new Key[2];
	private Core core;
	private EventManager evtMngr;
	private String name;
	private PollingTask task;

	public PollingKeyboardControllerSource(Core core, String name) {
		this.core = core;
		this.evtMngr = EventManager.getInstance(core);
		this.name = name;
		
		setAxisKeys(KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, KeyEvent.VK_UP, KeyEvent.VK_DOWN);
	}
	
	public void setAxisKeys(int left, int right, int up, int down) {
		InputManager inpMngr = InputManager.getInstance(this.core);
		this.hAxis[0] = new Key(inpMngr.getKeyState(left));
		this.hAxis[1] = new Key(inpMngr.getKeyState(right));
		this.vAxis[0] = new Key(inpMngr.getKeyState(up));
		this.vAxis[1] = new Key(inpMngr.getKeyState(down));
	}
	
	public void addAction(int actionKey) {
		InputManager inpMngr = InputManager.getInstance(this.core);
		this.actions.add(new Key(inpMngr.getKeyState(actionKey)));
	}
	
	public void engage() {
		this.task = new PollingTask(this.core);
		TaskManager.getInstance(this.core).attachTask(this.task);
	}
	
	public void disengage() {
		this.task.kill();
		this.task = null;
	}
	
	private void update() { 
		this.hAxis[0].update();
		if (this.hAxis[0].hasChanged()) {
			this.evtMngr.enqueueEvent(new TwoAxisController.HorizontalUpdateEvent(this.name, this.hAxis[0].isPressed() ? -1.0 : 0.0));			
		}
		
		this.hAxis[1].update();
		if (this.hAxis[1].hasChanged()) {
			this.evtMngr.enqueueEvent(new TwoAxisController.HorizontalUpdateEvent(this.name, this.hAxis[1].isPressed() ? 1.0 : 0.0));			
		}
		
		this.vAxis[0].update();
		if (this.vAxis[0].hasChanged()) {
			this.evtMngr.enqueueEvent(new TwoAxisController.VerticalUpdateEvent(this.name, this.vAxis[0].isPressed() ? 1.0 : 0.0));			
		}	
		
		this.vAxis[1].update();
		if (this.vAxis[1].hasChanged()) {
			this.evtMngr.enqueueEvent(new TwoAxisController.VerticalUpdateEvent(this.name, this.vAxis[1].isPressed() ? -1.0 : 0.0));			
		}
		
		int size = this.actions.size();
		for (int i = 0; i < size; ++i) {
			Key key = this.actions.get(i);
			key.update();
			if (key.hasChanged()) {
				this.evtMngr.enqueueEvent(new TwoAxisController.ActionUpdateEvent(this.name, key.isPressed(), i));								
			}
		}
	}
	
	private static class Key {
		private KeyState state;
		private boolean newState;
		private boolean oldState;
		private boolean changed;
		
		public Key(KeyState state) {
			this.state = state;
			this.newState = state.isPressed();
			this.oldState = this.newState;
		}
		
		public void update() {
			this.newState = state.isPressed();
			this.changed = this.newState != this.oldState;
			this.oldState = this.newState;
		}
		
		public boolean hasChanged() {
			return this.changed;
		}
		
		public boolean isPressed() {
			return this.newState;
		}
	}
	
	private class PollingTask extends AbstractTask {

		public PollingTask(Core core) {
			super(core);
		}

		@Override
		public void update() {
			PollingKeyboardControllerSource.this.update();
		}
	}
}
